#include <string.h>
#include "gzll.h"
#include "nrf_common.h"
#include "nrf_port.h"

/**
  Definition of the possible ways of selecting initial channel for a
  transmission.
*/
typedef enum {
    GZLL_CHANNEL_PREVIOUS_SUCCESS,              /*<上一个成功的频道*/
    GZLL_CHANNEL_RANDOM,                        /*<随机频道，通过gzll_lfsr_get*/
    GZLL_CHANNEL_ESTIMATED,                     /*<*预估的频道*/
    GZLL_CHANNEL_NEXT_INDEX                     /*<下一个频道*/
} gzll_new_tx_ch_t;

static void gzll_start_new_tx(gzll_new_tx_ch_t channel_select);
static void gzll_reload_tries_pr_channel_counter(void);
static void gzll_set_radio_auto_retries(void);
static void gzll_set_system_idle(void);

/*-----------------------------------------------------------------------------
  Channel Manager (CHM) function prototypes
-----------------------------------------------------------------------------*/
static void gzll_chm_reset_rx_channel_index(void);
static uint8_t gzll_chm_get_current_rx_channel(void);
static uint8_t gzll_chm_get_next_rx_channel(void);
static void gzll_chm_hold_rx_channel(void);
static void gzll_chm_execute(void);
static uint16_t gzll_chm_get_rx_ce_offset(void);
static uint16_t gzll_chm_get_tx_ce_offset(void);
static void gzll_set_radio_power_on(bool on);

static uint8_t gzll_lfsr_get(uint8_t seed, uint8_t max_limit);
/*-----------------------------------------------------------------------------
  Global variables
-----------------------------------------------------------------------------*/
/*
  Dynamic parameters.
*/
static uint16_t gzll_dyn_params[GZLL_DYN_PARAM_SIZE];                                           /*<用户配置的动态参数列表*/

/*
  Channel subset array.
*/
static uint8_t gzll_channel_tab[GZLL_DEFAULT_CHANNEL_TAB_SIZE] = GZLL_DEFAULT_CHANNEL_TAB;      /*<频道列表*/

/*
  Pipe 0 address shadow register.
*/
static uint8_t gzll_p0_adr[GZLL_ADDRESS_WIDTH] = GZLL_DEFAULT_ADDRESS_PIPE0;                    /*<pipe0通道的地址,一般情况都是使用pipe0进行通讯*/

/*
  Status variables.
*/
static uint8_t gzll_tx_success_f;                       // Result of previous transmission
static uint8_t gzll_tx_setup_modified;                  // TX setup modified since previous transmission
static uint8_t gzll_rx_setup_modified;                  // RX setup modified since previous receive session
static uint8_t gzll_sync_on;                            // Sync on
static uint8_t gzll_rx_dr;                              // Received data ready
static uint8_t gzll_rx_power_high_f;                    // Receive signal strength high
static uint8_t gzll_radio_active_f;                     // For assisting power management in application
static uint8_t gzll_power_on;

static uint8_t volatile gzll_current_tx_pipe;            // Current TX pipe setup
static uint8_t volatile gzll_current_tx_payload_length;  // Current TX payload length
static uint8_t volatile gzll_channel_tab_size;           // Channel subset size
static uint8_t volatile gzll_channel_tab_index;          // Channel subset index
static gzll_states_t volatile gzll_state_var;            // State variable

/*
  Variables for signaling to timer and radio ISR.
*/
static uint8_t gzll_pending_tx_start;                   // Transmission should be started in next timer ISR
static uint8_t gzll_pending_goto_idle;                  // Goto idle when current radio events completed
static uint8_t gzll_timer_period_modified;              // Timer period temporarily modified

/*
  FIFO holding receive pipes for ACK payloads
  residing in radio HW RX FIFO.
*/
static uint8_t gzll_ack_rx_pipe_fifo[3];                // FIFO holding pipe for received ACK payload
static uint8_t gzll_ack_rx_pipe_fifo_cnt;               // FIFO index

/*
  Counters.
*/
static uint8_t gzll_tries_pr_channel_counter;           // Counter used for counting transmit attempts before channel switch
static uint16_t gzll_sync_period;                       // Counter for counting duration since previous successfull TX
static uint16_t gzll_timeout_counter;                   // Counter used for TX/RX timeout

/*
  Transmission statistics.
*/
static uint16_t gzll_channel_switch_counter;            // Channel switches for previous transmission
static uint16_t gzll_try_counter;                       // Transmit attempts for previous transmission

/*-----------------------------------------------------------------------------
  Implementation: Application interface (user functions)
-----------------------------------------------------------------------------*/
// ==================================================================
/// @brief  : 初始化Gazell协议，这个必须被调用
// ==================================================================
void gzll_init(void)
{
    CE_LOW();

    hal_nrf_enable_ack_payload(true);               /*<使能载荷带ack*/
    hal_nrf_enable_dynamic_payload(true);           /*<使能动态载荷*/
    hal_nrf_setup_dynamic_payload(0xff);            /*<使能pipe动态载荷*/

    /*
    Initialize status variables.
    */
    gzll_channel_tab_index = 0;                     /*<频道列表*/
    gzll_channel_tab_size = GZLL_DEFAULT_CHANNEL_TAB_SIZE;

    gzll_pending_goto_idle = false;
    gzll_timer_period_modified = false;

    gzll_current_tx_pipe = 0;                       /*<当前pipe*/
    gzll_pending_tx_start = false;
    gzll_tx_setup_modified = true;
    gzll_rx_setup_modified = true;
    gzll_radio_active_f = false;
    gzll_tx_success_f = true;

    gzll_sync_period = 0;                           /*<同步时间*/
    gzll_sync_on = false;                           /*<默认是不同步*/

    gzll_rx_dr = false;
    gzll_rx_power_high_f = false;
    gzll_ack_rx_pipe_fifo_cnt = 0;

    /*
    Set up default addresses.
    */
    uint8_t tmp_addr[] = GZLL_DEFAULT_ADDRESS_PIPE0;
    memcpy(gzll_p0_adr, tmp_addr, 5);
    hal_nrf_set_address(HAL_NRF_PIPE0, gzll_p0_adr);                        /*<上电设置pipe默认地址*/

    /*
    Initialize dynamic parameters using default values.
    */
    gzll_dyn_params[GZLL_PARAM_DEVICE_MODE] = GZLL_DEFAULT_PARAM_DEVICE_MODE;
    gzll_dyn_params[GZLL_PARAM_TX_TIMEOUT] = GZLL_DEFAULT_PARAM_TX_TIMEOUT;
    gzll_dyn_params[GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_ON] = GZLL_DEFAULT_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_ON;
    gzll_dyn_params[GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_OFF] = GZLL_DEFAULT_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_OFF;
    gzll_dyn_params[GZLL_PARAM_HOST_MODE] = GZLL_DEFAULT_PARAM_HOST_MODE;
    gzll_dyn_params[GZLL_PARAM_RX_PIPES] = GZLL_DEFAULT_PARAM_RX_PIPES;
    gzll_dyn_params[GZLL_PARAM_CRYPT_PIPES] = GZLL_DEFAULT_PARAM_CRYPT_PIPES;
    gzll_dyn_params[GZLL_PARAM_RX_TIMEOUT] = GZLL_DEFAULT_PARAM_RX_TIMEOUT;
    gzll_dyn_params[GZLL_PARAM_HOST_MODE_1_CYCLE_PERIOD] = GZLL_DEFAULT_PARAM_HOST_MODE_1_CYCLE_PERIOD;
    gzll_dyn_params[GZLL_PARAM_RX_PERIOD] = GZLL_DEFAULT_PARAM_RX_PERIOD;
    gzll_dyn_params[GZLL_PARAM_RX_PERIOD_MODIFIER] = GZLL_DEFAULT_PARAM_RX_PERIOD_MODIFIER;
    gzll_dyn_params[GZLL_PARAM_RX_CHANNEL_HOLD_PERIODS] = GZLL_DEFAULT_PARAM_RX_CHANNEL_HOLD_PERIODS;
    gzll_dyn_params[GZLL_PARAM_OUTPUT_POWER] = GZLL_DEFAULT_PARAM_OUTPUT_POWER;
    gzll_dyn_params[GZLL_PARAM_POWER_DOWN_IDLE_ENABLE] = GZLL_DEFAULT_PARAM_POWER_DOWN_IDLE_ENABLE;
    gzll_dyn_params[GZLL_PARAM_MAX_SYNC_PERIOD] = GZLL_DEFAULT_PARAM_MAX_SYNC_PERIOD;
    gzll_dyn_params[GZLL_PARAM_COLLISION_CHANNEL_SWITCH_LIMIT] = GZLL_DEFAULT_PARAM_COLLISION_CHANNEL_SWITCH_LIMIT;

    /*
    Set up default output power.
    */
    hal_nrf_set_output_power((hal_nrf_output_power_t) gzll_dyn_params[GZLL_PARAM_OUTPUT_POWER]);      /*<设置输出功率*/

    /*
    Static radio setup.
    */
    hal_nrf_set_datarate(GZLL_HAL_DATARATE);                /*<设置通讯速率*/
    hal_nrf_set_crc_mode(GZLL_CRC);                         /*<设置CRC校验*/
    hal_nrf_set_address_width(GZLL_ADDRESS_WIDTH);          /*<设置地址宽度*/

    /*
    Clear radio IRQ flags.
    */
    hal_nrf_get_clear_irq_flags();                          /*<清除中断标志,status*/

    hal_nrf_flush_rx();                                     /*<清除发送和接收缓冲区*/
    hal_nrf_flush_tx();

    port_set_timer_period(GZLL_DEFAULT_PARAM_RX_PERIOD);    /*<设置定时器中断的周期->gzll_timer_isr_function*/
    gzll_set_system_idle();                                 /*<系统进入idle模式*/
}

// ==================================================================
/// @brief  : 用于设置动态协议参数
///
/// @param  : param 指定参数
/// @param  : value 设定值
// ==================================================================
void gzll_set_param(gzll_dyn_params_t param, uint16_t val)
{
    ASSERT((gzll_state_var == GZLL_IDLE));
    ASSERT((param < GZLL_DYN_PARAM_SIZE));
    ASSERT(!(param == GZLL_PARAM_DEVICE_MODE && val > GZLL_DEVICE_MODE_4));
    ASSERT(!(param == GZLL_PARAM_HOST_MODE && val > GZLL_HOST_MODE_1));
    ASSERT(!(param == GZLL_PARAM_RX_PIPES && val > 0x3f));
    // ASSERT(!(param == GZLL_PARAM_CRYPT_PIPES && val > GZLL_MAX_CRYPT_PIPES_VAL));
    ASSERT(!(param == GZLL_PARAM_OUTPUT_POWER && val > 3));

    if (param < GZLL_DYN_PARAM_SIZE) {
        gzll_dyn_params[param] = val;

        switch (param) {
            case GZLL_PARAM_DEVICE_MODE:
                if ((val == GZLL_DEVICE_MODE_0 || val == GZLL_DEVICE_MODE_1)) {
                    gzll_sync_on = false;
                }
                break;
            case GZLL_PARAM_POWER_DOWN_IDLE_ENABLE:
                if (val == 1) {
                    gzll_set_radio_power_on(false);
                }
                break;
            case GZLL_PARAM_RX_PERIOD:
                gzll_timer_period_modified = 1;
                break;
            case GZLL_PARAM_OUTPUT_POWER:
                hal_nrf_set_output_power((hal_nrf_output_power_t)gzll_dyn_params[GZLL_PARAM_OUTPUT_POWER]);
                break;
            case GZLL_PARAM_RX_PIPES:
                gzll_rx_setup_modified = true;
                break;
        }
    }
}

// ==================================================================
/// @brief  : 获取指定参数值
///
/// @param  : param 指定参数
///
/// @returns: 参数的设定值
// ==================================================================
uint16_t gzll_get_param(gzll_dyn_params_t param)
{
    ASSERT((param < GZLL_DYN_PARAM_SIZE));

    if (param < GZLL_DYN_PARAM_SIZE) {
        return gzll_dyn_params[param];
    } else {
        return 0;
    }
}

// ==================================================================
/// @brief  : 设置跳频频道列表
///
/// @param  : channels 频道列表
/// @param  : size 频道列表长度
// ==================================================================
void gzll_set_channels(uint8_t *channels, uint8_t channel_tab_size)
{

    ASSERT((gzll_state_var == GZLL_IDLE));
    ASSERT((channel_tab_size <= GZLL_DEFAULT_CHANNEL_TAB_SIZE));

    gzll_channel_tab_index = 0;
    gzll_channel_tab_size = channel_tab_size;
    memcpy(gzll_channel_tab, channels, gzll_channel_tab_size);

    hal_nrf_set_rf_channel(gzll_channel_tab[gzll_channel_tab_index]);       /*<默认使用第一个频道*/
}

// ==================================================================
/// @brief  : 设置指定通道地址
///
/// @param  : pipe 指定通道
/// @param  : address 地址缓存
// ==================================================================
void gzll_set_address(hal_nrf_address_t pipe, const uint8_t *address)
{
    ASSERT((gzll_state_var == GZLL_IDLE));
    ASSERT((pipe <= 5));

    gzll_tx_setup_modified = true;
    gzll_rx_setup_modified = true;        /*<更改了配置，nrf需要重新配置*/

    if (pipe == HAL_NRF_PIPE0) {
        memcpy(gzll_p0_adr, (uint8_t*)address, GZLL_ADDRESS_WIDTH);   /*<默认是使用pipe0通讯，协议只定义了p0_adr*/
    }

    hal_nrf_set_address(pipe, address);   /*<nrf设置pipe地址*/
}

// ==================================================================
/// @brief  : 获取指定通道地址
///
/// @param  : pipe 指定通道
/// @param  : address 地址缓存
// ==================================================================
void gzll_get_address(uint8_t pipe, uint8_t* address)
{
    ASSERT((pipe <= 5));
    ASSERT(address != NULL);

    hal_nrf_get_address(pipe, address); //lint !e534 "return value ignored"
}

#ifndef GZLL_DEVICE_ONLY
void gzll_rx_start(void)                                    /*<主机模式->主要是做数据接收，传输是通过ACK带载荷完成*/
{
    gzll_goto_idle();                           /*<首先修改状态为idle，只有在idle状态下才能改动当前运行状态*/

    if (gzll_rx_setup_modified) {               /*<如果配置有改变过，需求重新进行配置*/

        gzll_rx_setup_modified = false;
        gzll_tx_setup_modified = true;

        /*
        Restore pipe 0 address (this may have been altered during transmission)
        */
        hal_nrf_set_address(HAL_NRF_PIPE0, gzll_p0_adr);    /*<设置地址*/
        hal_nrf_set_operation_mode(HAL_NRF_PRX);            /*<配置为接收模式*/
    }

    gzll_set_radio_power_on(true);                          /*<配置nrf上电*/
    gzll_timeout_counter = 0;                               /*<收发计数器清0*/
    gzll_state_var = GZLL_HOST_ACTIVE;                      /*<改变状态为主机，主机主要做为接收*/

    CE_HIGH();
}

bool gzll_ack_payload_write(const uint8_t *src, uint8_t length, uint8_t pipe)     /*<ack载荷*/
{
    ASSERT(length <= GZLL_MAX_ACK_PAYLOAD_LENGTH && length > 0);
    ASSERT(pipe <= 5);

    if (length == 0 || (length > GZLL_MAX_ACK_PAYLOAD_LENGTH) || hal_nrf_tx_fifo_full()) {
        return false;                               // ACK payload not written
    }
    hal_nrf_write_ack_payload(pipe, src, length);   /*<向ACK包中写入载荷数据*/
    return true;                                    // ACK payload successfully written
}
#endif

#define GZLL_UPLOAD_PAYLOAD_TO_RADIO()                                  hal_nrf_write_tx_payload(src, length)

#ifndef GZLL_HOST_ONLY
// ==================================================================
/// @brief  : 设备发送数据,主机不能主动发送数据
///
/// @param  : src 数据包
/// @param  : length 数据包长度
/// @param  : pipe 指定通道
///
/// @returns:
// ==================================================================
bool gzll_tx_data(const uint8_t *src, uint8_t length, uint8_t pipe)
{
    uint16_t temp;

    ASSERT(length <= GZLL_MAX_FW_PAYLOAD_LENGTH && length > 0);
    ASSERT(pipe <= 5);

    /*
    Length check to prevent memory corruption. (Note, assertion
    will capture this as well).
    */
    if (length == 0 || length > GZLL_MAX_FW_PAYLOAD_LENGTH) {       /*<长度不大于最大载荷长度*/
        return false;
    }

    gzll_current_tx_payload_length = length;                        /*<保存当前数据长度*/

    if (gzll_state_var == GZLL_HOST_ACTIVE) {                       /*<主机不能主动发送数据*/
        gzll_goto_idle();
    }

    GZLL_INTERRUPTS_DISABLE();
    /*
    If the specified pipe is different from the previous TX pipe,
    the TX setup must be updated
    */
    if (pipe != gzll_current_tx_pipe) {                             /*<指定的发送pipe不是当前的发送pipe,配置参数被改了，需要重新设置参数*/
        gzll_current_tx_pipe = pipe;                                /*<设定当前tx pipe*/
        gzll_tx_setup_modified = true;
    }

    /*
    Here, state can be GZLL_IDLE or GZLL_DEVICE_ACTIVE
    */
    if (gzll_state_var == GZLL_IDLE) {                              /*<发送数据时，当前状态不可以是主机激活状态，其他的两种都有可能*/
        if (gzll_tx_setup_modified) {                               // TX setup has to be restored?
            gzll_tx_setup_modified = false;                         /*<重新配置参数*/
            gzll_rx_setup_modified = true;

            hal_nrf_set_operation_mode(HAL_NRF_PTX);                /*<配置为接收*/
            hal_nrf_open_pipe(HAL_NRF_PIPE0, EN_AA);                /*<开启pipe0自动应答*/

            //Read out the full RX address for pipe number "pipe"
            if (pipe == HAL_NRF_PIPE0) {                            /*<如果是用pipe0通道发送数据？*/
                hal_nrf_set_address(HAL_NRF_TX, gzll_p0_adr);       /*<设置发送和接收地址*/
                hal_nrf_set_address(HAL_NRF_PIPE0, gzll_p0_adr);
            }
        }

        // Prepare for new transmission
        gzll_timeout_counter = 0;
        gzll_channel_switch_counter = 0;
        gzll_try_counter = 0;                               /*<清零*/
        hal_nrf_flush_tx();                                 /*<将发送缓存清理*/

        GZLL_UPLOAD_PAYLOAD_TO_RADIO();                     /*<向发送缓存写入新的数据*/

        gzll_tx_success_f = false;                          // Transmission by default "failure"

        temp = gzll_dyn_params[GZLL_PARAM_DEVICE_MODE];     /*<获取设备工作模式*/

        gzll_set_radio_power_on(true);                      /*<配置nrf为上电状态*/
        if (gzll_sync_on) {                                 /*以上只对nrf进行了配置，并写入了有效数据，但是并没有进行数据发送*/
            switch(temp) {                                  /*数据发送是通过拉高CE脚，下面是对当前模式进行判断，然后最终是要控制CE脚才能进行数据发送*/
                case GZLL_DEVICE_MODE_2:
                default:                                    /*模式0-2，同步后默认先使用上一个频道发送数据*/
                    gzll_start_new_tx(GZLL_CHANNEL_PREVIOUS_SUCCESS);
                    break;
                case GZLL_DEVICE_MODE_3:
                    gzll_start_new_tx(GZLL_CHANNEL_RANDOM);
                    break;
                case GZLL_DEVICE_MODE_4:
                    gzll_start_new_tx(GZLL_CHANNEL_ESTIMATED);
                    break;
            }
        } else {                                            /*<设备没有同步上*/
            switch(temp) {
                case GZLL_DEVICE_MODE_0:                    /*模式0、2都是频率捷变，原则是先用上一个成功频道发送数据*/
                case GZLL_DEVICE_MODE_2:
                    gzll_start_new_tx(GZLL_CHANNEL_PREVIOUS_SUCCESS);
                    break;
                default:                                    /*<其他模式，没有同步使用随机频道发送数据*/
                    gzll_start_new_tx(GZLL_CHANNEL_RANDOM);
                    break;
            }
        }

        gzll_state_var = GZLL_DEVICE_ACTIVE;                /*<将状态设置为设备激活*/
        GZLL_INTERRUPTS_ENABLE();
        return true;                                        // Payload successfully written to TX FIFO
    } else {                                                // Else TRANSMIT state
        /*
        Check if criteria for starting new transmission when already transmitting
        is fulfilled
        */
        if (!gzll_tx_setup_modified && !hal_nrf_tx_fifo_full()) {
            GZLL_UPLOAD_PAYLOAD_TO_RADIO();                 /*<写入传输数据*/
            GZLL_INTERRUPTS_ENABLE();
            return true;                                    // Payload successfully written to TX FIFO
        } else {                                            /*<说明tx fifo是满的或是tx被重新设置过了,此时不能再进行传输*/
            GZLL_INTERRUPTS_ENABLE();
            return false;                                   // Payload not written to TX FIFO
        }
    }
}

// ==================================================================
/// @brief  : 检测发送是否成功，只有在IDLE情况下读取才有效
///
/// @returns: ture or not
// ==================================================================
bool gzll_tx_success(void)
{
    ASSERT(gzll_state_var != GZLL_DEVICE_ACTIVE);
    return gzll_tx_success_f;
}

// ==================================================================
/// @brief  : 获取tx重发尝试次数
///
/// @returns: 尝试次数
// ==================================================================
uint16_t gzll_get_tx_attempts(void)
{
    ASSERT(gzll_state_var != GZLL_DEVICE_ACTIVE);
    return gzll_try_counter;
}

// ==================================================================
/// @brief  : 获取tx频道切换次数
///
/// @returns: 切换次数
// ==================================================================
uint16_t gzll_get_tx_channel_switches(void)
{
    ASSERT(gzll_state_var != GZLL_DEVICE_ACTIVE);
    return  gzll_channel_switch_counter;
}
#endif

// ==================================================================
/// @brief  : 清理发送FIFO区
// ==================================================================
void gzll_tx_fifo_flush(void)
{
    hal_nrf_flush_tx();
}

// ==================================================================
/// @brief  : 获取当前状态
///
/// @returns: GZLL_IDLE, GZLL_DEVICE_ACTIVE, GZLL_HOST_ACTIVE
// ==================================================================
gzll_states_t gzll_get_state(void)
{
    return gzll_state_var;
}

// ==================================================================
/// @brief  : 获取已收到数据pipe通道
///
/// @returns: 有pipe有数据，则返回pipe编号，没有数据则返回0xff
// ==================================================================
uint8_t gzll_get_rx_data_ready_pipe_number(void)
{
    uint8_t dr_rx_pipe;                                 /*data ready->dr 接收pipe*/

    if (gzll_rx_dr) {                                   /*<是否接收到数据,这个是在radio中断中进行判断*/
        if(gzll_ack_rx_pipe_fifo_cnt > 0) {             /*<ack接收fifo计数器,nrf规定最大为3个缓冲区*/
            dr_rx_pipe = gzll_ack_rx_pipe_fifo[gzll_ack_rx_pipe_fifo_cnt - 1];
        } else {
            dr_rx_pipe = hal_nrf_get_rx_data_source();  /*<获取接收pipe源*/
        }
    } else {
        dr_rx_pipe = 0xff;
    }
    return dr_rx_pipe;
}

// ==================================================================
/// @brief  : 检测指定通道接收数据是否就绪
///
/// @param  : pipe 指定通道
///
/// @returns: ture or not
// ==================================================================
bool gzll_rx_data_ready(uint8_t pipe)
{
    uint8_t available_rx_data_pipe;

    available_rx_data_pipe = gzll_get_rx_data_ready_pipe_number();

    return (available_rx_data_pipe <= 5 && (pipe == 0xff || pipe == available_rx_data_pipe));
}

// ==================================================================
/// @brief  : 读取接收FIFO数据
///
/// @param  : dst 数据缓存
/// @param  : length 数据长度
/// @param  : pipe 指定通道
///
/// @returns: ture 读出数据，false 没有数据
// ==================================================================
bool gzll_rx_fifo_read(uint8_t *dst, uint8_t *length, uint8_t *pipe)
{
    uint8_t temp_pipe;
    uint8_t temp_length;
    uint16_t pipe_and_length;

    ASSERT(dst != NULL);

    if (gzll_rx_dr) {                                       /*是否接收到数据，在中断中被置位*/
        temp_length = hal_nrf_read_rx_payload_width();      /*<获取设置的接收数据宽度*/
        if (temp_length <= 32) {//TODO: Remove or comment hardcoded value
            pipe_and_length = hal_nrf_read_rx_payload(dst); /*<读取rx数据*/
            if (gzll_ack_rx_pipe_fifo_cnt > 0) {            /*<ack fifo计数器*/
                gzll_ack_rx_pipe_fifo_cnt--;
                temp_pipe = gzll_ack_rx_pipe_fifo[gzll_ack_rx_pipe_fifo_cnt];
            } else {
                temp_pipe = (pipe_and_length >> 8);         /*<左移8位才是数据长度*/
            }

            /*
            Handles if two or more payloads were received while only one interrupt
            request serviced.
            */
            if (hal_nrf_rx_fifo_empty()) {                  /*FIFO中没有数据，清零gzll_rx_dr*/
                gzll_rx_dr = false;
            }

            if (pipe != NULL) {                             /*<获取pipe号*/
                *pipe = temp_pipe;
            }

            if (length != NULL) {                           /*<获取长度*/
                *length = temp_length;
            }
            return true;
        } else {
            gzll_rx_fifo_flush();   /*>32,nrf不支持，清fifo*/
        }
    }
    return false;
}

// ==================================================================
/// @brief  : 检测接收信号质量
///
/// @returns: true if receive signal level >= -64 dBm.
/// @returns: false if receive signal level < -64 dBm.
// ==================================================================
bool gzll_rx_power_high(void)
{
    return gzll_rx_power_high_f;
}

// ==================================================================
/// @brief  : 获取通道列表大小
// ==================================================================
uint8_t gzll_get_channel_tab_size()
{
    return gzll_channel_tab_size;
}

// ==================================================================
/// @brief  : 获取通道列表
///
/// @param  : channels 通道缓存
// ==================================================================
void gzll_get_channels(uint8_t *channels)
{
    memcpy(channels, gzll_channel_tab, gzll_channel_tab_size);
}

// ==================================================================
/// @brief  : 清理接收FIFO区
// ==================================================================
void gzll_rx_fifo_flush(void)
{
    hal_nrf_flush_rx();
    gzll_ack_rx_pipe_fifo_cnt = 0;  /*<ack pipe计数器清0*/
    gzll_rx_dr = false;             /*<接收就绪标志清0*/
}

// ==================================================================
/// @brief  : 强制进入idle状态
// ==================================================================
void gzll_goto_idle(void)
{
    if (gzll_state_var == GZLL_DEVICE_ACTIVE) {     /*<如果当前状态为设备激活状态，也是说设备正在发送数据*/
        gzll_pending_goto_idle = true;              /*<通过设置变量方式，通知中断处理中关闭发送，让设备进入idle状态*/
        while(gzll_state_var != GZLL_IDLE){
            port_feed_wdt();
        }         /*<中断中会处理，这里进行等待强制设备进入idle状态*/
    } else {
        if (gzll_state_var == GZLL_HOST_ACTIVE) {   /*<如果当前状态为主机激活状态，也是说主机正在监听或正在接受数据*/
            gzll_set_system_idle();                 /*<设置系统进入idle*/
        }
    }
}

// ==================================================================
/// @brief  : 产生伪随机数
///
/// @param  : seed 随机数种子，如果是0，则不会改变序列
/// @param  : max_limit 最大返回值限定
///
/// @returns: 返回一个伪随机数
// ==================================================================
static uint8_t gzll_lfsr_get(uint8_t seed, uint8_t max_limit) /*<*/
{
    static uint8_t pseudoreg = 0xff; // Can never be zero
    uint8_t shiftbit;

    if (seed > 0) {
        pseudoreg = seed;
    }

    shiftbit = (pseudoreg << 7) & 0x80;
    shiftbit ^= (pseudoreg << 6) & 0x80;
    shiftbit ^= (pseudoreg << 5) & 0x80;
    shiftbit ^= (pseudoreg & 0x80);

    pseudoreg = (shiftbit | (pseudoreg >> 1));

    return pseudoreg % max_limit;
}

// ==================================================================
/// @brief  : 开始新的数据传输,主要是对频道进行选择
///
/// @param  : channel_select 频道选择策略
// ==================================================================
static void gzll_start_new_tx(gzll_new_tx_ch_t channel_select)
{
    uint8_t temp;       /*新的数据包发送，首先加载重发次数，设置重发延时时间，在选择频道，在根据是否同步在进行数据发送<重点是在同步这里>*/

    gzll_reload_tries_pr_channel_counter();                 /*<重载重发计数器*/
    gzll_set_radio_auto_retries();                          /*<设置自动重发间隔时间*/

    // If new random channel should be picked
    switch (channel_select) {
        case GZLL_CHANNEL_PREVIOUS_SUCCESS:
        default:
            temp = gzll_channel_tab_index;                  /*<使用上一个成功发送的频道*/
            break;
        case GZLL_CHANNEL_RANDOM:
            temp = gzll_lfsr_get(0, gzll_channel_tab_size); /*<随机产生新的频道*/
            break;
        case GZLL_CHANNEL_ESTIMATED:                        /*<预估下一个频道*/
            temp = gzll_chm_get_next_rx_channel();
            break;
        case GZLL_CHANNEL_NEXT_INDEX:                       /*<直接选取下个频道*/
            temp = gzll_channel_tab_index + 1;
            temp = temp % gzll_channel_tab_size;
            break;
    }
    // Update RF channel if new is different from current
    if  (temp != gzll_channel_tab_index) {                  /*<如果新的频道不是当前保存的频道*/
        gzll_channel_tab_index = temp;                      /*<记录下新的频道，并设置通讯频道*/
        hal_nrf_set_rf_channel(gzll_channel_tab[gzll_channel_tab_index]);
        gzll_channel_switch_counter++;                      /*<通讯频道计数器++*/
    }

    if (gzll_sync_on) {
        // Signal to timer ISR for starting a new transmission
        gzll_pending_tx_start = true;     /*<同步后发送，是要计算间隔时间，所以在中断中控制发送*/
    } else {
        gzll_radio_active_f = true;       /*<没有同步，数据是尝试发送，可以立刻发送，然后检测在做重传*/
        GZLL_RFCE_PULSE();
    }
}

// ==================================================================
/// @brief  : 重载每个通道重发次数，分为同步或不同步的状态的次数
// ==================================================================
static void gzll_reload_tries_pr_channel_counter(void)
{
    if (gzll_sync_on) {                              /*<根据是否同步区别每个通道发送次数*/
        gzll_tries_pr_channel_counter = gzll_dyn_params[GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_ON];
    } else {
        gzll_tries_pr_channel_counter = gzll_dyn_params[GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_OFF];
    }
}

// ==================================================================
/// @brief  : 设置nrf重发间隔延时时间
// ==================================================================
static void gzll_set_radio_auto_retries(void)
{
    if (gzll_tries_pr_channel_counter > 15) {       /*<nrf规定是最大15次重发*/
        hal_nrf_set_auto_retr(15, GZLL_AUTO_RETR_DELAY);
    } else {
        hal_nrf_set_auto_retr((uint8_t)(gzll_tries_pr_channel_counter - 1), GZLL_AUTO_RETR_DELAY);
    }
}

// ==================================================================
/// @brief  : 配置系统进入IDLE状态
// ==================================================================
static void gzll_set_system_idle(void)
{
    CE_LOW();

    if (gzll_state_var == GZLL_HOST_ACTIVE) {       /*<如果是主机激活状态，可能还在响应设备ACK，等待一段时间让ack发送出去*/
        // Add delay to ensure that any ongoing ACK transmission is completed.
        port_delay_rx_periods(5*GZLL_HOST_CE_LOW_IDLE_DELAY);
    }

    if (gzll_dyn_params[GZLL_PARAM_POWER_DOWN_IDLE_ENABLE]) { /*<IDLE后是否直接进入掉电模式*/
        gzll_set_radio_power_on(false);
    } else {
        gzll_set_radio_power_on(true);
    }

    gzll_radio_active_f = false;        /*<设置radio没有激活*/
    gzll_pending_goto_idle = false;     /*<idle挂起取消*/
    gzll_state_var = GZLL_IDLE;         /*<设置状态为idle*/
}

// ==================================================================
/// @brief  : nrf IRQ中断处理函数，nrf必须要配置为中断模式，用户在配置的中断调用
// ==================================================================
void gzll_radio_isr_function(void)
{
#ifndef GZLL_HOST_ONLY
    //lint -esym(644,tries) "Variable may not have been initialized"
    uint8_t tries;
    uint16_t timer_mod_period, temp;
#endif
    uint8_t status;

    GZLL_INTERRUPTS_DISABLE();

    status = hal_nrf_clear_irq_flags_get_status();  /*<读取中断状态*/
    //If "received data ready" interrupt from radio
    if (status & ((1<<RX_DR))) {    /*<接收到数据*/
        gzll_rx_dr = true;          /*<设置接收到数据标志,中断中并不读取数据，由应用程序主动调用读取函数*/
        gzll_rx_power_high_f = hal_nrf_get_carrier_detect();    /*<载波检测*/
        gzll_chm_hold_rx_channel(); /*<设置保持当前通道一段时间，原因是当前通道接收到了数据，属于同步了*/

#ifndef GZLL_HOST_ONLY
        /*
        If ACK payload has been received . Here, the actual RX pipe is always 0, so
        rx_pipe_fifo[] needs to store the current tx pipe.
        */
        if(gzll_state_var == GZLL_DEVICE_ACTIVE) {                                      /*<设备可以保持3个ack fifo*/
            gzll_ack_rx_pipe_fifo[gzll_ack_rx_pipe_fifo_cnt] = gzll_current_tx_pipe;    /*<保存当前tx pipe*/
            if (gzll_ack_rx_pipe_fifo_cnt < 2) {
                gzll_ack_rx_pipe_fifo_cnt++;
            }
        }
#endif
    }

  //Read radio retransmit attempt counter and update affected variables.
#ifndef GZLL_HOST_ONLY
    if ((status & (1<<MAX_RT)) || (status & ((1<<TX_DS)))) {        /*<重发最大次数或发送完成*/
        tries = hal_nrf_get_transmit_attempts() + 1;                /*<读取nrf寄存器中的重发计数器*/
        //gzll_tries_pr_channel_counter -= tries;                   /*<更新每个通道的重发计数器*/
        (gzll_tries_pr_channel_counter > tries) ? (gzll_tries_pr_channel_counter -= tries) : (gzll_tries_pr_channel_counter = 0);
        gzll_try_counter += tries;                                  /*<更新发送计数器*/
    }
#endif

  //If "data sent" interrupt from radio
    if (status & (1<<TX_DS)) {                                      /*<数据发送完成*/
#ifndef GZLL_HOST_ONLY
        if (gzll_state_var == GZLL_DEVICE_ACTIVE) {                 /*<设备激活状态*/
            gzll_timer_period_modified = 1;                         /*定时器周期被改变*/
            timer_mod_period = gzll_dyn_params[GZLL_PARAM_RX_PERIOD] - (gzll_dyn_params[GZLL_PARAM_RX_PERIOD_MODIFIER] + ((uint16_t)((GZLL_CONST_BYTES_PR_PACKET * 2) + gzll_current_tx_payload_length) * GZLL_US_PR_BYTE));

            if (status & ((1<<RX_DR))) {                            /*<如果接收到数据*/
                timer_mod_period -= (GZLL_US_PR_BYTE * GZLL_INTERNAL_ACK_PAYLOAD_LENGTH);
            }

            port_set_timer_period(timer_mod_period);                /*<重设定时器中断周期*/

            gzll_chm_reset_rx_channel_index();                      /*<复位接收频道*/
            gzll_chm_hold_rx_channel();                             /*<保持当前通道，当前通道已成功发送数据*/

            temp = gzll_dyn_params[GZLL_PARAM_DEVICE_MODE];         /*<获取设备当前模式*/

            gzll_sync_period = gzll_dyn_params[GZLL_PARAM_MAX_SYNC_PERIOD];     /*<获取同步周期,只有设备在办同步模式下设置才有作用*/

            if (temp == GZLL_DEVICE_MODE_2 || temp == GZLL_DEVICE_MODE_3 || temp == GZLL_DEVICE_MODE_4) {
                gzll_sync_on = true;                                /*接收到数据，证明已经同步了*/
            }

            /*
            Goto IDLE state if TX FIFO empty.
            */
            if (hal_nrf_tx_fifo_empty()) {  /*<在设备激活状态，接收到应答数据后，fifo缓存没有数据就可以进入idle了*/
                gzll_tx_success_f = true;
                gzll_set_system_idle();
            } else {                        /*<tx fifo还有数据，继续发送*/
                gzll_reload_tries_pr_channel_counter();
                gzll_timeout_counter = 0;
                gzll_try_counter = 0;       /*<清零计数变量*/
                GZLL_RFCE_PULSE();
            }
        }
#endif
    }

  /*
  If "max retransmit" interrupt from radio
  */
#ifndef GZLL_HOST_ONLY
    if (status & (1<<MAX_RT)) {                                 /*<重发达了nrf配置的最大次数*/
        CE_LOW();

        gzll_timeout_counter += tries;                          /*<重发次数累加*/
        temp = gzll_dyn_params[GZLL_PARAM_TX_TIMEOUT];

        // If TX has timed out, or user has called gzll_goto_idle()
        if ((temp != 0 && gzll_timeout_counter >= temp) || gzll_pending_goto_idle) {  /*<重发达到最大次数或有进入idle挂起状态*/
            gzll_set_system_idle();
        } else {
            // If tries per channel has elapsed
            if (gzll_tries_pr_channel_counter == 0) {           /*<当前频道重发次数已经到了*/
                // If possible unintended sync to another device
                if (gzll_channel_switch_counter > gzll_dyn_params[GZLL_PARAM_COLLISION_CHANNEL_SWITCH_LIMIT]) {    /*<已到最大通道且切换次数*/
                    gzll_sync_period = 0;
                    gzll_sync_on = false;
                    gzll_start_new_tx(GZLL_CHANNEL_RANDOM);     /*<切换一个频道*/
                } else {
                    if(gzll_sync_on) {  /*<同步了*/
                        // If < 1 timer period until radio active -> state shall not go to !radio_active
                        if(gzll_chm_get_tx_ce_offset() > 1) {
                            gzll_radio_active_f = false;        /*<用来判断radio是否激活了，没有实际作用*/
                        }
                        gzll_start_new_tx(GZLL_CHANNEL_ESTIMATED);  /*<同步了，先判断当前通道是否可以继续发，否则切到下个频道*/
                    } else {
                        gzll_start_new_tx(GZLL_CHANNEL_NEXT_INDEX); /*<没有同步，直接使用下一个频道发送*/
                    }
                }
            } else {
                gzll_set_radio_auto_retries();      // Continue retransmits on same channel
                GZLL_RFCE_PULSE();                  /*<ce拉高10us以上，进入发送状态*/
            }
        }
    }
#endif
    GZLL_INTERRUPTS_ENABLE();
}

// ==================================================================
/// @brief  : 定时器处理函数，设备主要管理数据发送和跳频
// ==================================================================
void gzll_timer_isr_function(void)
{
    uint16_t temp;

    GZLL_INTERRUPTS_DISABLE();
    gzll_chm_execute();                         // Execute radio channel manager

    // If timer period temporaly modified - restore correct setting.
#ifndef GZLL_HOST_ONLY
    if (gzll_timer_period_modified == 1) {
        port_set_timer_period(gzll_dyn_params[GZLL_PARAM_RX_PERIOD]);
        gzll_timer_period_modified = 0;
    }
#endif

  // If receive state
#ifndef GZLL_DEVICE_ONLY
    if (gzll_state_var == GZLL_HOST_ACTIVE) {   /*<主机通过定时器中断来执行跳频*/
        temp = gzll_chm_get_current_rx_channel();      // Get channel radio should be monitoring

        // If new channel should be monitored
        if (temp != gzll_channel_tab_index) {
            CE_LOW();
            hal_nrf_set_rf_channel(gzll_channel_tab[temp]); // Change channel
            CE_HIGH();                              // Set CE high here to minimize RX off time
            gzll_channel_tab_index = temp;          /*<切换接收频道*/
        }

        temp = gzll_chm_get_rx_ce_offset();       // Get number of periods until CE should be set high

        // Radio CE handling
        if (gzll_chm_get_rx_ce_offset() == 0) {      // 主机处理ce状态
            gzll_set_radio_power_on(true);
            gzll_radio_active_f = true;
            CE_HIGH();
        } else {
            CE_LOW();
            gzll_radio_active_f = false;
            gzll_set_radio_power_on(false);
        }
        gzll_timeout_counter++;

        temp = gzll_dyn_params[GZLL_PARAM_RX_TIMEOUT];
        if (gzll_dyn_params[GZLL_PARAM_RX_TIMEOUT] > 0 && (gzll_timeout_counter >= temp)) {      /*<GZLL_PARAM_RX_TIMEOUT 设为0，则主机不会进入idle*/
            gzll_set_system_idle();
        }
    }
    else
#endif
    {
    // If transmit state
#ifndef GZLL_HOST_ONLY
        if (gzll_state_var == GZLL_DEVICE_ACTIVE) {
        // If pending TX payload
            if (gzll_pending_tx_start) {   /*<如果有数据要发送，这个变量主要用来发送数据，在中断中才会被判断*/
                temp = gzll_chm_get_tx_ce_offset();

                if( !gzll_sync_on || (temp == 0 && (gzll_channel_tab_index == gzll_chm_get_current_rx_channel()))) {
                    GZLL_RFCE_PULSE();
                    gzll_radio_active_f = true;
                    gzll_pending_tx_start = 0;
                }
            }
        }
#endif
    }

#ifndef GZLL_HOST_ONLY
    if (gzll_sync_period > 0) {   /*<tx成功的持续时间,是通过参数设置的*/
        gzll_sync_period--;       /*<发送成功后开始--*/
    } else {
        gzll_sync_on = false;     /*<如果tx传输成功周期为0，则表示当前没有同步上了*/
    }
#endif

    GZLL_INTERRUPTS_ENABLE();
}

/*-----------------------------------------------------------------------------
-----------------------------------------------------------------------------*/
static uint8_t gzll_chm_rx_channel_index = 0;     /*<接收频道索引*/
static uint8_t gzll_chm_hold_rx_channel_index = 0;/*<接收保持计数器，主要是为了减少同步或是发送失败次数，发送或接收成功就在当前通道保持一段时间*/
static uint16_t gzll_chm_rx_channel_hold = 0;     /*<接收频道保持计数器*/
static uint16_t gzll_chm_rx_mode1_sequence = 0;   /*<主机设置为低功耗模式，用来计数判断主机是否该处于接收或休眠状态*/

// ==================================================================
/// @brief  : gzll频道管理器，用来选择下个频道
// ==================================================================
static void gzll_chm_execute(void)
{
    if (gzll_chm_rx_channel_hold > 0) {   /*<频道保持计数器*/
        gzll_chm_rx_channel_hold--;
    }

    // Increment channel synchronization counters
    gzll_chm_rx_mode1_sequence = (gzll_chm_rx_mode1_sequence + 1) % gzll_dyn_params[GZLL_PARAM_HOST_MODE_1_CYCLE_PERIOD];
    /*<如果主机是低延时模式，进行频道轮询数据*/
    if ((gzll_dyn_params[GZLL_PARAM_HOST_MODE] == GZLL_HOST_MODE_0) || (gzll_chm_rx_mode1_sequence == 0)) {
        gzll_chm_rx_channel_index = (gzll_chm_rx_channel_index + 1) % gzll_channel_tab_size;  /*<切换频道, 一直在进行频道切换*/
    }
}

// ==================================================================
/// @brief  : gzll复位接收频道索引，主要用于设备同步主机
// ==================================================================
static void gzll_chm_reset_rx_channel_index(void)
{
    gzll_chm_rx_channel_index = gzll_channel_tab_index;
    gzll_chm_rx_mode1_sequence = 0;
}

// ==================================================================
/// @brief  : gzll获取下个频道索引值
// ==================================================================
static uint8_t gzll_chm_get_next_rx_channel(void)
{
    if(gzll_chm_rx_channel_hold > 1) {       /*<如果设置了接收通道保持计数器，则可以直接使用上个频道传输*/
        return gzll_chm_hold_rx_channel_index;
    } else {
        return (gzll_chm_rx_channel_index + 1) % gzll_channel_tab_size; /*<否则，就切到下个频道*/
    }
}

// ==================================================================
/// @brief  : gzll获取当前的接收频道索引值
// ==================================================================
static uint8_t gzll_chm_get_current_rx_channel(void)
{
    if (gzll_chm_rx_channel_hold > 0) {    /*<如果当前接收频道保持计数不为0，则返回保持的频道*/
        return gzll_chm_hold_rx_channel_index;
    } else {
        return gzll_chm_rx_channel_index;
    }
}

// ==================================================================
/// @brief  : gzll设置频道保持时间
// ==================================================================
static void gzll_chm_hold_rx_channel(void)        /*<设置频道保持时间*/
{
    gzll_chm_rx_channel_hold = gzll_dyn_params[GZLL_PARAM_RX_CHANNEL_HOLD_PERIODS];   /*<获取设置的频道保持时间*/
    gzll_chm_hold_rx_channel_index = gzll_channel_tab_index;                          /*频道管理器频道索引保存当前的通讯频道*/
}

// ==================================================================
/// @brief  : gzll获取控制发送状态的CE脚状态
// ==================================================================
static uint16_t gzll_chm_get_tx_ce_offset(void)   /*<获取tx ce状态*/
{
    if ((gzll_dyn_params[GZLL_PARAM_HOST_MODE] == GZLL_HOST_MODE_0) || (gzll_chm_rx_channel_hold > 0)) {
        return 0;       // CE always high in mode 0
    } else {
        // Low power RX sequence
        if (gzll_chm_rx_mode1_sequence == 0) {
            return 0;
        } else {
            return (gzll_dyn_params[GZLL_PARAM_HOST_MODE_1_CYCLE_PERIOD] - gzll_chm_rx_mode1_sequence);
        }
    }
}

// ==================================================================
/// @brief  : gzll获取控制接收状态的CE脚状态
// ==================================================================
static uint16_t gzll_chm_get_rx_ce_offset(void)   /*获取rx ce状态*/
{
    uint16_t total_tx_time_per_channel;
    uint16_t rx_periods_per_channel;

    if (gzll_dyn_params[GZLL_PARAM_HOST_MODE] == GZLL_HOST_MODE_0 || (gzll_chm_rx_channel_hold > 0)) {
        return 0;       // CE always high in mode 0, or during "channel hold"
    } else {
        if (gzll_chm_rx_mode1_sequence == 0) {
            return 0;
        } else {
            total_tx_time_per_channel = gzll_dyn_params[GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_OFF] * GZLL_TYP_TX_PERIOD;
            rx_periods_per_channel = total_tx_time_per_channel / gzll_dyn_params[GZLL_PARAM_RX_PERIOD];

            if (gzll_chm_rx_mode1_sequence <= (gzll_channel_tab_size * rx_periods_per_channel)) {
                return ((rx_periods_per_channel - (gzll_chm_rx_mode1_sequence % rx_periods_per_channel)) - 1);
            } else {
                return (gzll_dyn_params[GZLL_PARAM_HOST_MODE_1_CYCLE_PERIOD] - gzll_chm_rx_mode1_sequence);
            }
        }
    }
}

// ==================================================================
/// @brief  : gzll设置nrf电源状态
/// @param  : on 开或关
// ==================================================================
static void gzll_set_radio_power_on(bool on)
{
    uint8_t n;

    if (on) {
        if (!gzll_power_on) {
            hal_nrf_set_power_mode(HAL_NRF_PWR_UP);
            n = 3;
            while(n--) {}
            gzll_power_on = true;
        }
    } else {
        hal_nrf_set_power_mode(HAL_NRF_PWR_DOWN);
        gzll_power_on = false;
    }
}
